[v1.x] Preserve the exact OAuth resource indicator (backport #2925) - #3462
Draft
pcarleton wants to merge 2 commits into
Draft
[v1.x] Preserve the exact OAuth resource indicator (backport #2925)#3462pcarleton wants to merge 2 commits into
pcarleton wants to merge 2 commits into
Conversation
(cherry picked from commit b7a5bff)
The 1.x line still allows pydantic 2.11 (Python < 3.14), where the url_preserve_empty_path config from #2925 is silently ignored and a path-less PRM resource still renders with a trailing slash. Record the wire string on ProtectedResourceMetadata (resource_str) and use it for the resource parameter, so the client echoes the server's identifier verbatim on every supported pydantic version. Also spell the config as a cast dict so the 2.11 type stubs accept it, and make the cherry-picked issuer assertion version-tolerant. Co-Authored-By: Claude <noreply@anthropic.com>
9 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #2925 to the 1.x line, plus a small compat shim so the fix holds on pydantic < 2.12 (which 1.x still supports).
Motivation and Context
RFC 8707's
resourceparameter must be the protected resource's identifier byte-for-byte. On 1.x a path-lessresourcefrom the server's Protected Resource Metadata (http://host:port) is parsed intoAnyHttpUrland re-serialised ashttp://host:port/, so the client sends a different identifier in the authorization and token requests (#2578).mainfixed this in #2925 viaurl_preserve_empty_path=Trueon the OAuth metadata models; that was never backported.This now matters for conformance: modelcontextprotocol/conformance#488 adds a
resource-parameter-matches-prmcheck (FAILURE, RFC 8707 MUST) to the scoredauth/metadata-var2client scenario, and the 1.x line fails it without this change whilemain, go, rust, csharp and the TS SDK pass.What's in here
url_preserve_empty_path=TrueonOAuthClientMetadata,OAuthMetadata,ProtectedResourceMetadata; the v2 migration-guide hunk is dropped since that file doesn't exist on 1.x).lowest-directCI leg) still resolves pydantic 2.11, whereurl_preserve_empty_pathis silently ignored.ProtectedResourceMetadatanow records the wire string (resource_str) andOAuthContext.get_resource_url()/_validate_resource_matchuse it, so theresourceparameter is echoed verbatim on every supported pydantic version. The config is spelled as a cast dict so the 2.11 type stubs accept it, and the cherry-picked issuer assertion is made version-tolerant.How Has This Been Tested?
uv run --frozen pytest tests/client/test_auth.py→ 129 passed (new testtest_get_resource_url_echoes_pathless_prm_resource_verbatim); ruff + pyright clean on the touched files; behaviour checked on pydantic 2.11.7 and 2.13.4.client --scenario auth/metadata-var2 --spec-version 2025-11-25with.github/actions/conformance/client.py:resource-parameter-matches-prm FAILURE→ scenario FAILEDresource-parameter-matches-prm SUCCESS, 18/18 checks, scenario PASSED;auth/metadata-defaultPASSED before and after.Breaking Changes
None intended.
str(prm.resource)is unchanged on pydantic < 2.12 (still normalised); code that needs the exact identifier should use the newProtectedResourceMetadata.resource_str.Types of changes
Checklist
AI Disclaimer
Prepared with Claude Code; reviewed the diff and the test/conformance output.